#include <iostream>
#include <unistd.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc.hpp>
#include <fstream>
#include <vector>

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d; // 添加此命名空间

int main(int argc, char **argv)
{

    // 读取目标图像和模板
    cv::Mat img = cv::imread("images/image.jpg");
    cv::Mat template_img = cv::imread("images/template.jpg");
    cv::Mat img_gray = imread("images/image.jpg", IMREAD_GRAYSCALE);
    cv::Mat template_gray = imread("images/template.jpg", IMREAD_GRAYSCALE);

    if (img_gray.empty() || template_gray.empty())
    {
        cout << "Could not open or find the images!" << endl;
        return -1;
    }

    // 初始化SIFT检测器
    Ptr<SIFT> sift = SIFT::create(0, 3, 0.04, 10, 1.6);

    // 找到关键点和描述符
    vector<KeyPoint> kp1, kp2;
    Mat des1, des2;
    sift->detectAndCompute(img_gray, noArray(), kp1, des1);
    sift->detectAndCompute(template_gray, noArray(), kp2, des2);

    // 使用FLANN匹配器
    FlannBasedMatcher matcher;
    vector<vector<DMatch>> matches;
    matcher.knnMatch(des1, des2, matches, 2);

    // 筛选好的匹配点
    vector<DMatch> good_matches;
    for (int i = 0; i < matches.size(); ++i)
    {
        if (matches[i][0].distance < 0.7 * matches[i][1].distance)
        {
            good_matches.push_back(matches[i][0]);
        }
    }

    // 将数据转换为 Mat 格式，以便进行聚类
    cv::Mat data(kp1.size(), 2, CV_32F);
    for (size_t i = 0; i < kp1.size(); ++i)
    {
        data.at<float>(i, 0) = kp1[i].pt.x; // 使用 pt 属性获取 x 坐标
        data.at<float>(i, 1) = kp1[i].pt.y; // 使用 pt 属性获取 y 坐标
    }

    // 将数据标准化，以便更好地应用 DBSCAN
    cv::Mat scaled_data;
    cv::normalize(data, scaled_data, 0, 1, cv::NORM_MINMAX);

    // 创建 DBSCAN 聚类器
    // 设置 eps 参数为距离阈值，min_samples 参数为簇中最少的点数
    // 这里不需要手动设置 eps 和 min_samples 的值，而是根据数据特性自动确定
    cv::Ptr<cv::ml::DBSCAN> dbscan = cv::ml::DBSCAN::create();

    // 使用 DBSCAN 对数据进行聚类
    cv::Mat labels;
    dbscan->setMinClusterSize(5); // 设置簇中最少的点数
    dbscan->setEps(0.5);          // 设置距离阈值
    dbscan->cluster(scaled_data, labels);

    // 查看聚类结果
    std::cout << "聚类结果：" << labels << std::endl;

    // 获取簇的数量（不包括噪声点）
    int n_clusters = static_cast<int>(cv::sum(labels != -1)[0]);
    std::cout << "簇的数量：" << n_clusters << std::endl;

    // 使用DBSCAN聚类算法对匹配点进行聚类
    if (!good_matches.empty())
    {
        vector<Point2f> points1, points2;
        for (auto &match : good_matches)
        {
            points1.push_back(kp1[match.queryIdx].pt);
            points2.push_back(kp2[match.trainIdx].pt);
        }

        Mat mask;
        vector<int> labels;
        int num_clusters = partition(points1, labels, [&](const Point2f &a, const Point2f &b)
                                     {
                                         return norm(a - b) < 50; // 设置阈值
                                     });

        // 绘制匹配结果
        Mat img_matches;
        drawMatches(img, kp1, template_img, kp2, good_matches, img_matches, Scalar::all(-1),
                    Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

        // 绘制聚类簇和中心点
        for (int i = 0; i < num_clusters; ++i)
        {
            vector<Point2f> cluster_points1, cluster_points2;
            for (int j = 0; j < good_matches.size(); ++j)
            {
                if (labels[j] == i)
                {
                    cluster_points1.push_back(points1[j]);
                    cluster_points2.push_back(points2[j]);
                }
            }

            // 绘制模板的位置
            Mat H = findHomography(cluster_points2, cluster_points1, RANSAC);
            vector<Point2f> template_corners(4), transformed_corners(4);
            template_corners[0] = Point2f(0, 0);
            template_corners[1] = Point2f(0, template_img.rows);
            template_corners[2] = Point2f(template_img.cols, template_img.rows);
            template_corners[3] = Point2f(template_img.cols, 0);
            perspectiveTransform(template_corners, transformed_corners, H);
            for (int j = 0; j < 4; ++j)
            {
                line(img_matches, transformed_corners[j], transformed_corners[(j + 1) % 4], Scalar(0, 255, 0), 2);
            }

            Point2f center(0, 0);
            for (int j = 0; j < 4; ++j)
            {
                center.x += transformed_corners[j].x;
                center.y += transformed_corners[j].y;
            }
            center.x /= 4;
            center.y /= 4;

            // 绘制中心点
            circle(img_matches, center, 5, Scalar(0, 0, 255), -1);
        }

        cv::imwrite("images/result.jpg", img_matches);
    }
    else
    {
        cout << "No good matches found." << endl;
    }

    return 0;
}